/*
 * @(#) $Header$
 *
 * Copyright (C) 2006  Daniel Léonard
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package ca.forklabs.baselib.util;

import ca.forklabs.baselib.util.predicate.AlwaysTrue;
import ca.forklabs.baselib.util.predicate.Bind1stPredicate;
import ca.forklabs.baselib.util.predicate.Bind2ndPredicate;
import ca.forklabs.baselib.util.predicate.UnaryAnd;
import ca.forklabs.baselib.util.predicate.BinaryNegate;
import ca.forklabs.baselib.util.predicate.UnaryOr;
import ca.forklabs.baselib.util.predicate.UnaryNegate;

/**
 * Class {@code Predicates} provides factory methods to create predicates.
 *
 * @author <a href="mailto:forklabs at gmail.com?subject=ca.forklabs.baselib.util.Predicates">Daniel Léonard</a>
 * @version $Revision$
 */
public class Predicates {

//---------------------------
// Constructor
//---------------------------

   /**
    * Let no one instanciate this class.
    */
   private Predicates() {
   // nothing
      }

//---------------------------
// Class methods
//---------------------------

   /**
    * Generates a predicate that always evaluates to {@code true}.
    * @param   <A>   the type of the argument.
    * @return   the always true predicate.
    */
   public static <A> UnaryPredicate<A> alwaysTrue() {
      UnaryPredicate<A> always_true = new AlwaysTrue<>();
      return always_true;
      }

   /**
    * Generates a predicate that always evaluates to {@code false}.
    * @param   <A>   the type of the argument.
    * @return   the always false predicate.
    */
   public static <A> UnaryPredicate<A> alwaysFalse() {
      UnaryPredicate<A> always_true = Predicates.alwaysTrue();
      UnaryPredicate<A> always_false = Predicates.not1(always_true);
      return always_false;
      }

   /**
    * Makes a predicate that always negates the specified predicate.
    * @param <A>   the type of the object the predicate evaluates.
    * @param predicate   the predicate.
    * @return   the negation of the predicate.
    */
   public static <A> UnaryPredicate<A> not1(UnaryPredicate<A> predicate) {
      UnaryPredicate<A> negation = new UnaryNegate<>(predicate);
      return negation;
      }

   /**
    * Makes a predicate that always negates the specified predicate.
    * @param   <A1>   the type of the first argument object.
    * @param   <A2>   the type of the second argument object.
    * @param predicate   the predicate.
    * @return   the negation of the predicate.
    */
   public static <A1, A2> BinaryPredicate<A1, A2> not2(BinaryPredicate<A1, A2> predicate) {
      BinaryPredicate<A1, A2> negation = new BinaryNegate<>(predicate);
      return negation;
      }

   /**
    * Makes a composite predicates evaluates a list of predicate with a
    * short-circuits "and".
    * @param   <A>   the type of the object the predicate evaluates.
    * @param   predicates   the list of predicates.
    * @return   the composite short-circuit "and" predicate.
    */
   @SafeVarargs
   public static <A> UnaryPredicate<A> and(UnaryPredicate<A>... predicates) {
      UnaryPredicate<A> predicate = new UnaryAnd<>(predicates);
      return predicate;
      }

   /**
    * Makes a composite predicates evaluates a list of predicate with a
    * short-circuits "and".
    * @param   <A>   the type of the object the predicate evaluates.
    * @param   predicates   the list of predicates.
    * @return   the composite short-circuit "and" predicate.
    */
   public static <A> UnaryPredicate<A> and(Iterable<UnaryPredicate<A>> predicates) {
      UnaryPredicate<A> predicate = new UnaryAnd<>(predicates);
      return predicate;
      }

   /**
    * Makes a composite predicates evaluates a list of predicate with a
    * short-circuits "or".
    * @param   <A>   the type of the object the predicate evaluates.
    * @param   predicates   the list of predicates.
    * @return   the composite short-circuit "or" predicate.
    */
   @SafeVarargs
   public static <A> UnaryPredicate<A> or(UnaryPredicate<A>... predicates) {
      UnaryPredicate<A> predicate = new UnaryOr<>(predicates);
      return predicate;
      }

   /**
    * Makes a composite predicates evaluates a list of predicate with a
    * short-circuits "or".
    * @param   <A>   the type of the object the predicate evaluates.
    * @param   predicates   the list of predicates.
    * @return   the composite short-circuit "or" predicate.
    */
   public static <A> UnaryPredicate<A> or(Iterable<UnaryPredicate<A>> predicates) {
      UnaryPredicate<A> predicate = new UnaryOr<>(predicates);
      return predicate;
      }

   /**
    * Makes <em>f(c, x)</em>.
    * @param   <A1>   the type of the first argument object.
    * @param   <A2>   the type of the second argument object.
    * @param   predicate   the binary predicate.
    * @param   arg1   the binded first argument.
    * @return   a bind1st predicate.
    */
   public static <A1, A2> UnaryPredicate<A2> bind1st(BinaryPredicate<A1, A2> predicate, A1 arg1) {
      UnaryPredicate<A2> bind1st = new Bind1stPredicate<>(predicate, arg1);
      return bind1st;
      }

   /**
    * Makes <em>f(x, c)</em>.
    * @param   <A1>   the type of the first argument object.
    * @param   <A2>   the type of the second argument object.
    * @param   predicate   the binary predicate.
    * @param   arg2   the binded second argument.
    * @return   a bind2nd predicate.
    */
   public static <A1, A2> UnaryPredicate<A1> bind2nd(BinaryPredicate<A1, A2> predicate, A2 arg2) {
      UnaryPredicate<A1> bind2nd = new Bind2ndPredicate<>(predicate, arg2);
      return bind2nd;
      }

   }
